home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 1 (Walnut Creek)
/
Aminet - June 1993 [Walnut Creek].iso
/
usenet
/
sources
/
volume91
/
utilitys
/
less_14z
/
part04
< prev
next >
Wrap
Internet Message Format
|
1991-07-08
|
51KB
Path: news.larc.nasa.gov!amiga-request
From: amiga-request@ab20.larc.nasa.gov (Amiga Sources/Binaries Moderator)
Subject: v91i130: Less 1.4Z - text pager, Part04/07
Reply-To: rayz@altair.csustan.edu (R. L. Zarling)
Newsgroups: comp.sources.amiga
Message-ID: <comp.sources.amiga.v91i130@ab20.larc.nasa.gov>
References: <comp.sources.amiga.v91i127@ab20.larc.nasa.gov>
Date: 04 Jul 91 17:28:18 GMT
Approved: tadguy@uunet.UU.NET (Tad Guy)
X-Mail-Submissions-To: amiga@uunet.uu.net
X-Post-Discussions-To: comp.sys.amiga.misc
Submitted-by: rayz@altair.csustan.edu (R. L. Zarling)
Posting-number: Volume 91, Issue 130
Archive-name: utilities/less-1.4z/part04
#!/bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g.. If this archive is complete, you
# will see the following message at the end:
# "End of archive 4 (of 7)."
# Contents: Less1.4Z/src/line.c Less1.4Z/src/prim.c
# Wrapped by tadguy@ab20 on Thu Jul 4 13:28:15 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'Less1.4Z/src/line.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'Less1.4Z/src/line.c'\"
else
echo shar: Extracting \"'Less1.4Z/src/line.c'\" \(24485 characters\)
sed "s/^X//" >'Less1.4Z/src/line.c' <<'END_OF_FILE'
X/*
X * Routines to manipulate the "line buffer".
X * The line buffer holds a line of output as it is being built
X * in preparation for output to the screen.
X * We keep track of the PRINTABLE length of the line as it is being built.
X */
X
X#ifdef AMIGA
X/* Compile with -HPreHeader.q to get "less.h"! */
X#else
X#include "less.h"
X#endif
X
X
Xstatic char linebuf[1024]; /* Buffer which holds the current output line */
Xstatic char *curr; /* Pointer into linebuf */
Xstatic int column; /* Printable length, accounting for
X backspaces, etc. */
X/*
X * A ridiculously complex state machine takes care of backspaces
X * when in BS_SPECIAL mode. The complexity arises from the attempt
X * to deal with all cases, especially involving long lines with underlining,
X * boldfacing or whatever. There are still some cases which will break it.
X *
X * If ANSIGR is defined, we also recognized ANSI Graphic Rendition commands
X * for underline, boldface, italics, and inverse video. As with the
X * backspace modes, the emulation is imperfect and can be broken under
X * certain rare circumstances.
X *
X * There are five (four, if not ANSIGR) states:
X * LN_NORMAL is the normal state (not in underline mode).
X * LN_UNDERLINE means we are in underline mode. We expect to get
X * either a sequence like "_\bX" or "X\b_" to continue
X * underline mode, or anything else to end underline mode.
X * LN_BOLDFACE means we are in boldface mode. We expect to get sequences
X * like "X\bX\b...X\bX" to continue boldface mode, or anything
X * else to end boldface mode.
X * LN_UL_X means we are one character after LN_UNDERLINE
X * (we have gotten the '_' in "_\bX" or the 'X' in "X\b_").
X * LN_UL_XB means we are one character after LN_UL_X
X * (we have gotten the backspace in "_\bX" or "X\b_";
X * we expect one more ordinary character,
X * which will put us back in state LN_UNDERLINE).
X * LN_BO_X means we are one character after LN_BOLDFACE
X * (we have gotten the 'X' in "X\bX").
X * LN_BO_XB means we are one character after LN_BO_X
X * (we have gotten the backspace in "X\bX";
X * we expect one more 'X' which will put us back
X * in LN_BOLDFACE).
X *ifdef ANSIGR
X * LN_CSI means we are in an ANSI Graphic Rendition sequence.
X * Variable AnsiLen is the number of characters we have seen
X * before this one in this sequence. AnsiMode is the numeric
X * value of the first character after the CSI.
X *endif
X */
Xstatic int ln_state; /* Currently in normal/underline/bold/etc mode? */
X#define LN_NORMAL 0 /* Not in underline, boldface or whatever mode */
X#define LN_UNDERLINE 1 /* In underline, need next char */
X#define LN_UL_X 2 /* In underline, got char, need \b */
X#define LN_UL_XB 3 /* In underline, got char & \b, need one more */
X#define LN_BOLDFACE 4 /* In boldface, need next char */
X#define LN_BO_X 5 /* In boldface, got char, need \b */
X#define LN_BO_XB 6 /* In boldface, got char & \b, need same char */
X#ifdef ANSIGR
X#define LN_CSI 7 /* In an Ansi Graphic Rendition sequence */
X
Xstatic int AnsiLen, AnsiMode, AnsiNum;
X#endif
X
Xpublic char *line; /* Pointer to the current line.
X Usually points to linebuf. */
X
Xextern int bs_mode;
Xextern int tabstop;
Xextern int bo_width, be_width;
Xextern int ul_width, ue_width;
X#ifdef AMIGA
Xextern int it_width, ie_width;
Xextern int nv_width, ne_width;
X#endif
Xextern int sc_width, sc_height;
X
X/*
X * Rewind the line buffer.
X */
X#ifdef __STDC__
Xvoid prewind (void)
X#else
X public void
Xprewind()
X#endif
X{
X line = curr = linebuf;
X ln_state = LN_NORMAL;
X column = 0;
X}
X
X/*
X * Append a character to the line buffer.
X * Expand tabs into spaces, handle underlining, boldfacing, etc.
X * Returns 0 if ok, 1 if couldn't fit in buffer.
X */
X
X#ifdef AMIGA
X/* ue_width is zero on the Amiga */
X#define NEW_COLUMN(newcol) if ((newcol) > sc_width) \
X return (1); else column = (newcol)
X
X#else
X#define NEW_COLUMN(newcol) if ((newcol) + ((ln_state)?ue_width:0) > sc_width) \
X return (1); else column = (newcol)
X#endif
X
X#ifdef __STDC__
Xint pappend (int c)
X#else
X public int
Xpappend(c)
X int c;
X#endif
X{
X if (c == '\0')
X {
X /*
X * Terminate any special modes, if necessary.
X * Append a '\0' to the end of the line.
X */
X switch (ln_state)
X {
X case LN_UL_X:
X curr[0] = curr[-1];
X curr[-1] = UE_CHAR;
X curr++;
X break;
X case LN_BO_X:
X curr[0] = curr[-1];
X curr[-1] = BE_CHAR;
X curr++;
X break;
X case LN_UL_XB:
X case LN_UNDERLINE:
X *curr++ = UE_CHAR;
X break;
X case LN_BO_XB:
X case LN_BOLDFACE:
X *curr++ = BE_CHAR;
X break;
X }
X ln_state = LN_NORMAL;
X *curr = '\0';
X return (0);
X }
X
X if (curr > linebuf + sizeof(linebuf) - 12)
X /*
X * Almost out of room in the line buffer.
X * Don't take any chances.
X * {{ Linebuf is supposed to be big enough that this
X * will never happen, but may need to be made
X * bigger for wide screens or lots of backspaces. }}
X */
X return (1);
X
X if (bs_mode == BS_SPECIAL)
X {
X /*
X * Advance the state machine.
X */
X switch (ln_state)
X {
X#ifdef ANSIGR
X case LN_CSI:
X /* interpret an ANSI control string. We have seen an ESC
X or CSI (0x9b) and possibly some more characters that
X make a valid prefix of an ANSI set-graphics-mode cmd.
X As long as the prefix remains valid, nothing is put in
X the line buffer. This avoids the buffer overflowing
X before we reach the end of some long ANSI sequence.
X If we get an invalid character in the sequence, we
X start printing control characters with the first thing
X we did not recognize.
X */
X if ( c == '[' && AnsiLen == 1 ) /* esc-[ ? */
X return 0;
X if ( c == ';' || c == 'm' )
X if ( AnsiNum >= 0 && AnsiNum < 8 )
X AnsiMode = AnsiNum;
X if ( !isdigit(c) )
X AnsiNum = -1;
X if ( c == 'm' ) /* end of sequence ? */
X {
X ln_state = LN_NORMAL;
X switch ( AnsiMode )
X {
X /* Note: several NEW_COLUMN lines are commented
X out in the following code. Even though this is
X Amiga-specific code, the 'column' *should* be
X reset in each of these cases. It just so
X happens that all the xx_width are zero, so the
X whole thing is academic.
X */
X case -1: /* no mode set */
X return 0;
X case 0: /* normal */
X *curr++ = UE_CHAR;
X /* NEW_COLUMN(column+ue_width); */
X return 0;
X case 1: /* bold */
X *curr++ = BO_CHAR;
X /* NEW_COLUMN(column+bo_width); */
X return 0;
X case 3: /* Italic */
X *curr++ = IT_CHAR;
X /* NEW_COLUMN(column+it_width); */
X return 0;
X case 4: /* underline */
X *curr++ = UL_CHAR;
X /* NEW_COLUMN(column+ul_width); */
X return 0;
X case 7: /* inverse video */
X *curr++ = NV_CHAR;
X /* NEW_COLUMN(column+nv_width); */
X return 0;
X default: return 0;
X }
X }
X else if ( isdigit(c) )
X {
X AnsiLen++;
X if (AnsiNum < 0) AnsiNum = 0;
X AnsiNum *= 10;
X AnsiNum += c - '0';
X return 0;
X }
X else if ( c == ';' )
X {
X AnsiLen++;
X return 0;
X }
X else ln_state = LN_NORMAL;
X /* v v v fall through v v v */
X#endif
X case LN_NORMAL:
X#ifdef ANSIGR
X if ( (unsigned char)c == 0x9b || c == 0x1b )
X {
X ln_state = LN_CSI;
X AnsiMode = -1;
X AnsiLen = 1;
X AnsiNum = -1;
X return 0;
X }
X#endif
X if (curr <= linebuf + 1 || curr[-1] != '\b')
X break;
X
X if (c == curr[-2])
X goto enter_boldface;
X if (c == '_' || curr[-2] == '_')
X goto enter_underline;
X curr -= 2;
X break;
X
Xenter_boldface:
X /*
X * We have "X\bX" (including the current char).
X * Switch into boldface mode.
X */
X if (column + bo_width + be_width + 1 >= sc_width)
X /*
X * Not enough room left on the screen to
X * enter and exit boldface mode.
X */
X return (1);
X
X if (bo_width > 0 &&
X curr > linebuf + 2 && curr[-3] == ' ')
X {
X /*
X * Special case for magic cookie terminals:
X * if the previous char was a space, replace
X * it with the "enter boldface" sequence.
X */
X curr[-3] = BO_CHAR;
X column += bo_width-1;
X } else
X {
X curr[-1] = curr[-2];
X curr[-2] = BO_CHAR;
X column += bo_width;
X curr++;
X }
X goto ln_bo_xb_case;
X
Xenter_underline:
X /*
X * We have either "_\bX" or "X\b_" (including
X * the current char). Switch into underline mode.
X */
X if (column + ul_width + ue_width + 1 >= sc_width)
X /*
X * Not enough room left on the screen to
X * enter and exit underline mode.
X */
X return (1);
X
X if (ul_width > 0 &&
X curr > linebuf + 2 && curr[-3] == ' ')
X {
X /*
X * Special case for magic cookie terminals:
X * if the previous char was a space, replace
X * it with the "enter underline" sequence.
X */
X curr[-3] = UL_CHAR;
X column += ul_width-1;
X } else
X {
X curr[-1] = curr[-2];
X curr[-2] = UL_CHAR;
X column += ul_width;
X curr++;
X }
X goto ln_ul_xb_case;
X /*NOTREACHED*/
X case LN_UL_XB:
X /*
X * Termination of a sequence "_\bX" or "X\b_".
X */
X if (c != '_' && curr[-2] != '_' && c == curr[-2])
X {
X /*
X * We seem to have run on from underlining
X * into boldfacing - this is a nasty fix, but
X * until this whole routine is rewritten as a
X * real DFA, ... well ...
X */
X curr[0] = curr[-2];
X curr[-2] = UE_CHAR;
X curr[-1] = BO_CHAR;
X curr += 2; /* char & non-existent backspace */
X ln_state = LN_BO_XB;
X goto ln_bo_xb_case;
X }
Xln_ul_xb_case:
X if (c == '_')
X c = curr[-2];
X curr -= 2;
X ln_state = LN_UNDERLINE;
X break;
X case LN_BO_XB:
X /*
X * Termination of a sequnce "X\bX".
X */
X if (c != curr[-2] && (c == '_' || curr[-2] == '_'))
X {
X /*
X * We seem to have run on from
X * boldfacing into underlining.
X */
X curr[0] = curr[-2];
X curr[-2] = BE_CHAR;
X curr[-1] = UL_CHAR;
X curr += 2; /* char & non-existent backspace */
X ln_state = LN_UL_XB;
X goto ln_ul_xb_case;
X }
Xln_bo_xb_case:
X curr -= 2;
X ln_state = LN_BOLDFACE;
X break;
X case LN_UNDERLINE:
X if (column + ue_width + bo_width + 1 + be_width >= sc_width)
X /*
X * We have just barely enough room to
X * exit underline mode and handle a possible
X * underline/boldface run on mixup.
X */
X return (1);
X ln_state = LN_UL_X;
X break;
X case LN_BOLDFACE:
X if (c == '\b')
X {
X ln_state = LN_BO_XB;
X break;
X }
X if (column + be_width + ul_width + 1 + ue_width >= sc_width)
X /*
X * We have just barely enough room to
X * exit underline mode and handle a possible
X * underline/boldface run on mixup.
X */
X return (1);
X ln_state = LN_BO_X;
X break;
X case LN_UL_X:
X if (c == '\b')
X ln_state = LN_UL_XB;
X else
X {
X /*
X * Exit underline mode.
X * We have to shuffle the chars a bit
X * to make this work.
X */
X curr[0] = curr[-1];
X curr[-1] = UE_CHAR;
X column += ue_width;
X if (ue_width > 0 && curr[0] == ' ')
X /*
X * Another special case for magic
X * cookie terminals: if the next
X * char is a space, replace it
X * with the "exit underline" sequence.
X */
X column--;
X else
X curr++;
X ln_state = LN_NORMAL;
X }
X break;
X case LN_BO_X:
X if (c == '\b')
X ln_state = LN_BO_XB;
X else
X {
X /*
X * Exit boldface mode.
X * We have to shuffle the chars a bit
X * to make this work.
X */
X curr[0] = curr[-1];
X curr[-1] = BE_CHAR;
X column += be_width;
X if (be_width > 0 && curr[0] == ' ')
X /*
X * Another special case for magic
X * cookie terminals: if the next
X * char is a space, replace it
X * with the "exit boldface" sequence.
X */
X column--;
X else
X curr++;
X ln_state = LN_NORMAL;
X }
X break;
X }
X }
X
X if (c == '\t')
X {
X /*
X * Expand a tab into spaces.
X */
X do
X {
X NEW_COLUMN(column+1);
X } while ((column % tabstop) != 0);
X *curr++ = '\t';
X return (0);
X }
X
X if (c == '\b')
X {
X if (bs_mode == BS_CONTROL)
X {
X /*
X * Treat backspace as a control char: output "^H".
X */
X NEW_COLUMN(column+2);
X#ifdef EIGHTBIT
X *curr++ = c;
X#else
X *curr++ = ('H' | 0200);
X#endif
X } else
X {
X /*
X * Output a real backspace.
X */
X column--;
X *curr++ = '\b';
X }
X return (0);
X }
X
X if (control_char(c))
X {
X /*
X * Put a "^X" into the buffer.
X * The 0200 bit is used to tell put_line() to prefix
X * the char with a ^. We don't actually put the ^
X * in the buffer because we sometimes need to move
X * chars around, and such movement might separate
X * the ^ from its following character.
X * {{ This should be redone so that we can use an
X * 8 bit (e.g. international) character set. }}
X */
X NEW_COLUMN(column+2);
X *curr++ =
X#ifdef EIGHTBIT
X c;
X#else
X (carat_char(c) | 0200);
X#endif
X return (0);
X }
X
X /*
X * Ordinary character. Just put it in the buffer.
X */
X NEW_COLUMN(column+1);
X *curr++ = c;
X return (0);
X}
X
X/*
X * Analogous to forw_line(), but deals with "raw lines":
X * lines which are not split for screen width.
X * {{ This is supposed to be more efficient than forw_line(). }}
X */
X#ifdef __STDC__
XPOSITION forw_raw_line (POSITION curr_pos)
X#else
X public POSITION
Xforw_raw_line(curr_pos)
X POSITION curr_pos;
X#endif
X{
X register char *p;
X register int c;
X POSITION new_pos;
X
X if (curr_pos == NULL_POSITION || ch_seek(curr_pos) ||
X (c = ch_forw_get()) == EOF)
X return (NULL_POSITION);
X
X p = linebuf;
X
X for (;;)
X {
X if (c == '\n' || c == EOF)
X {
X new_pos = ch_tell();
X break;
X }
X if (p >= &linebuf[sizeof(linebuf)-1])
X {
X /*
X * Overflowed the input buffer.
X * Pretend the line ended here.
X * {{ The line buffer is supposed to be big
X * enough that this never happens. }}
X */
X new_pos = ch_tell() - 1;
X break;
X }
X *p++ = c;
X c = ch_forw_get();
X }
X *p = '\0';
X line = linebuf;
X return (new_pos);
X}
X
X/*
X * Analogous to back_line(), but deals with "raw lines".
X * {{ This is supposed to be more efficient than back_line(). }}
X */
X#ifdef __STDC__
XPOSITION back_raw_line (POSITION curr_pos)
X#else
X public POSITION
Xback_raw_line(curr_pos)
X POSITION curr_pos;
X#endif
X{
X register char *p;
X register int c;
X POSITION new_pos;
X
X if (curr_pos == NULL_POSITION || curr_pos <= (POSITION)0 ||
X ch_seek(curr_pos-1))
X return (NULL_POSITION);
X
X p = &linebuf[sizeof(linebuf)];
X *--p = '\0';
X
X for (;;)
X {
X c = ch_back_get();
X if (c == '\n')
X {
X /*
X * This is the newline ending the previous line.
X * We have hit the beginning of the line.
X */
X new_pos = ch_tell() + 1;
X break;
X }
X if (c == EOF)
X {
X /*
X * We have hit the beginning of the file.
X * This must be the first line in the file.
X * This must, of course, be the beginning of the line.
X */
X new_pos = (POSITION)0;
X break;
X }
X if (p <= linebuf)
X {
X /*
X * Overflowed the input buffer.
X * Pretend the line ended here.
X */
X new_pos = ch_tell() + 1;
X break;
X }
X *--p = c;
X }
X line = p;
X return (new_pos);
X}
END_OF_FILE
if test 24485 -ne `wc -c <'Less1.4Z/src/line.c'`; then
echo shar: \"'Less1.4Z/src/line.c'\" unpacked with wrong size!
fi
# end of 'Less1.4Z/src/line.c'
fi
if test -f 'Less1.4Z/src/prim.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'Less1.4Z/src/prim.c'\"
else
echo shar: Extracting \"'Less1.4Z/src/prim.c'\" \(22479 characters\)
sed "s/^X//" >'Less1.4Z/src/prim.c' <<'END_OF_FILE'
X/*
X * Primitives for displaying the file on the screen.
X */
X
X#ifdef AMIGA
X#define REGCMP 1
X#define regex regexec
X#define regcmp(x,y) regcomp(x)
X#include "regexp.h"
X#endif
X
X#ifdef AMIGA
X/* Compile with -HPreHeader.q to get "less.h"! */
X#else
X#include "less.h"
X#endif
X
X#include "position.h"
X
X
Xpublic int hit_eof; /* Keeps track of how many times we hit end of file */
X
Xextern int quiet;
Xextern int top_search;
Xextern int top_scroll;
Xextern int back_scroll;
Xextern int sc_width, sc_height;
Xextern int sigs;
Xextern int quit_at_eof;
Xextern int ac;
Xextern char *line;
Xextern char *first_cmd;
X
X/* Prototypes for functions defined in prim.c */
X
Xstatic void eof_bell __PROTO((void));
Xstatic void eof_check __PROTO((void));
Xstatic void forw __PROTO((register int n,
X POSITION pos,
X int force,
X int only_last));
Xstatic void back __PROTO((register int n,
X POSITION pos,
X int force,
X int only_last));
Xstatic void prepaint __PROTO((POSITION pos));
Xstatic int badmark __PROTO((int c));
Xstatic int match __PROTO((char *pattern,
X char *buf));
X
X
X
X/*
X * Sound the bell to indicate he is trying to move past end of file.
X */
X#ifdef __STDC__
Xstatic void eof_bell (void)
X#else
X static void
Xeof_bell()
X#endif
X{
X if (quiet == NOT_QUIET)
X bell();
X else
X vbell();
X}
X
X/*
X * Check to see if the end of file is currently "displayed".
X */
X#ifdef __STDC__
Xstatic void eof_check (void)
X#else
X static void
Xeof_check()
X#endif
X{
X POSITION pos;
X
X /*
X * If the bottom line is empty, we are at EOF.
X * If the bottom line ends at the file length,
X * we must be just at EOF.
X */
X pos = position(BOTTOM_PLUS_ONE);
X if (pos == NULL_POSITION || pos == ch_length())
X hit_eof++;
X}
X
X/*
X * Display n lines, scrolling forward,
X * starting at position pos in the input file.
X * "force" means display the n lines even if we hit end of file.
X * "only_last" means display only the last screenful if n > screen size.
X */
X#ifdef __STDC__
Xstatic void forw (register int n, POSITION pos, int force, int only_last)
X#else
X static void
Xforw(n, pos, force, only_last)
X register int n;
X POSITION pos;
X int force;
X int only_last;
X#endif
X{
X int eof = 0;
X int nlines = 0;
X int do_repaint;
X static int first_time = 1;
X
X /*
X * do_repaint tells us not to display anything till the end,
X * then just repaint the entire screen.
X */
X do_repaint = (only_last && n > sc_height-1);
X
X if (!do_repaint)
X {
X if (top_scroll && n >= sc_height - 1)
X {
X /*
X * Start a new screen.
X * {{ This is not really desirable if we happen
X * to hit eof in the middle of this screen,
X * but we don't yet know if that will happen. }}
X */
X if (top_scroll == 2)
X clear();
X home();
X force = 1;
X } else
X {
X lower_left();
X clear_eol();
X }
X
X if (pos != position(BOTTOM_PLUS_ONE))
X {
X /*
X * This is not contiguous with what is
X * currently displayed. Clear the screen image
X * (position table) and start a new screen.
X */
X pos_clear();
X add_forw_pos(pos);
X force = 1;
X if (top_scroll)
X {
X if (top_scroll == 2)
X clear();
X home();
X } else if (!first_time)
X {
X putstr("...skipping...\n");
X }
X }
X }
X
X while (--n >= 0)
X {
X /*
X * Read the next line of input.
X */
X pos = forw_line(pos);
X if (pos == NULL_POSITION)
X {
X /*
X * End of file: stop here unless the top line
X * is still empty, or "force" is true.
X */
X eof = 1;
X if (!force && position(TOP) != NULL_POSITION)
X break;
X line = NULL;
X }
X /*
X * Add the position of the next line to the position table.
X * Display the current line on the screen.
X */
X add_forw_pos(pos);
X nlines++;
X if (do_repaint ||
X (first_time && line == NULL && !top_scroll))
X continue;
X if (top_scroll == 1)
X clear_eol();
X put_line();
X }
X
X if (eof)
X hit_eof++;
X else
X eof_check();
X if (nlines == 0)
X eof_bell();
X else if (do_repaint)
X repaint();
X#ifndef AMIGA
X if (first_time && hit_eof && quit_at_eof && ac <= 1)
X quit();
X#endif
X first_time = 0;
X}
X
X/*
X * Display n lines, scrolling backward.
X */
X#ifdef __STDC__
Xstatic void back (register int n, POSITION pos, int force, int only_last)
X#else
X static void
Xback(n, pos, force, only_last)
X register int n;
X POSITION pos;
X int force;
X int only_last;
X#endif
X{
X int nlines = 0;
X int do_repaint;
X
X do_repaint = (n > get_back_scroll() || (only_last && n > sc_height-1));
X hit_eof = 0;
X while (--n >= 0)
X {
X /*
X * Get the previous line of input.
X */
X pos = back_line(pos);
X if (pos == NULL_POSITION)
X {
X /*
X * Beginning of file: stop here unless "force" is true.
X */
X if (!force)
X break;
X line = NULL;
X }
X /*
X * Add the position of the previous line to the position table.
X * Display the line on the screen.
X */
X add_back_pos(pos);
X nlines++;
X if (!do_repaint)
X {
X home();
X add_line();
X put_line();
X }
X }
X
X eof_check();
X if (nlines == 0)
X eof_bell();
X else if (do_repaint)
X repaint();
X}
X
X/*
X * Display n more lines, forward.
X * Start just after the line currently displayed at the bottom of the screen.
X */
X#ifdef __STDC__
Xvoid forward (int n, int only_last)
X#else
X public void
Xforward(n, only_last)
X int n;
X int only_last;
X#endif
X{
X POSITION pos;
X
X pos = position(BOTTOM_PLUS_ONE);
X if (pos == NULL_POSITION)
X {
X eof_bell();
X hit_eof++;
X return;
X }
X forw(n, pos, 0, only_last);
X}
X
X/*
X * Display n more lines, backward.
X * Start just before the line currently displayed at the top of the screen.
X */
X#ifdef __STDC__
Xvoid backward (int n, int only_last)
X#else
X public void
Xbackward(n, only_last)
X int n;
X int only_last;
X#endif
X{
X POSITION pos;
X
X pos = position(TOP);
X if (pos == NULL_POSITION)
X {
X /*
X * This will almost never happen,
X * because the top line is almost never empty.
X */
X eof_bell();
X return;
X }
X back(n, pos, 0, only_last);
X}
X
X/*
X * Repaint the screen, starting from a specified position.
X */
X#ifdef __STDC__
Xstatic void prepaint (POSITION pos)
X#else
X static void
Xprepaint(pos)
X POSITION pos;
X#endif
X{
X hit_eof = 0;
X forw(sc_height-1, pos, 1, 0);
X}
X
X/*
X * Repaint the screen.
X */
X#ifdef __STDC__
Xvoid repaint (void)
X#else
X public void
Xrepaint()
X#endif
X{
X /*
X * Start at the line currently at the top of the screen
X * and redisplay the screen.
X */
X#ifndef AMIGA
X /* screen might have been resized */
X POSITION savepos;
X
X savepos = position(TOP);
X pos_clear();
X add_forw_pos(savepos);
X prepaint(savepos);
X#else
X prepaint(position(TOP));
X#endif
X}
X
X/*
X * Jump to the end of the file.
X * It is more convenient to paint the screen backward,
X * from the end of the file toward the beginning.
X */
X#ifdef __STDC__
Xvoid jump_forw (void)
X#else
X public void
Xjump_forw()
X#endif
X{
X POSITION pos;
X
X if (ch_end_seek())
X {
X error("Cannot seek to end of file");
X return;
X }
X lastmark();
X pos = ch_tell();
X clear();
X pos_clear();
X add_back_pos(pos);
X back(sc_height - 1, pos, 0, 0);
X}
X
X/*
X * Jump to line n in the file.
X */
X#ifdef __STDC__
Xvoid jump_back (register int n)
X#else
X public void
Xjump_back(n)
X register int n;
X#endif
X{
X register int c;
X int nlines;
X
X /*
X * This is done the slow way, by starting at the beginning
X * of the file and counting newlines.
X */
X if (ch_seek((POSITION)0))
X {
X /*
X * Probably a pipe with beginning of file no longer buffered.
X * If he wants to go to line 1, we do the best we can,
X * by going to the first line which is still buffered.
X */
X if (n <= 1 && ch_beg_seek() == 0)
X jump_loc(ch_tell());
X error("Cannot get to beginning of file");
X return;
X }
X
X /*
X * Start counting lines.
X */
X for (nlines = 1; nlines < n; nlines++)
X {
X while ((c = ch_forw_get()) != '\n')
X if (c == EOF)
X {
X char message[40];
X sprintf(message, "File has only %d lines",
X nlines-1);
X error(message);
X return;
X }
X }
X
X jump_loc(ch_tell());
X}
X
X/*
X * Jump to a specified percentage into the file.
X * This is a poor compensation for not being able to
X * quickly jump to a specific line number.
X */
X#ifdef __STDC__
Xvoid jump_percent (int percent)
X#else
X public void
Xjump_percent(percent)
X int percent;
X#endif
X{
X POSITION pos, len;
X register int c;
X
X /*
X * Determine the position in the file
X * (the specified percentage of the file's length).
X */
X if ((len = ch_length()) == NULL_POSITION)
X {
X error("Don't know length of file");
X return;
X }
X pos = (percent * len) / 100;
X
X /*
X * Back up to the beginning of the line.
X */
X if (ch_seek(pos) == 0)
X {
X while ((c = ch_back_get()) != '\n' && c != EOF)
X ;
X if (c == '\n')
X (void) ch_forw_get();
X pos = ch_tell();
X }
X jump_loc(pos);
X}
X
X/*
X * Jump to a specified position in the file.
X */
X#ifdef __STDC__
Xvoid jump_loc (POSITION pos)
X#else
X public void
Xjump_loc(pos)
X POSITION pos;
X#endif
X{
X register int nline;
X POSITION tpos;
X
X /*
X * See if the desired line is BEFORE the currently
X * displayed screen. If so, see if it is close enough
X * to scroll backwards to it.
X * {{ This can be expensive if he has specified a very
X * large back_scroll count. Perhaps we should put
X * some sanity limit on the loop count here. }}
X */
X tpos = position(TOP);
X if (tpos != NULL_POSITION && pos < tpos)
X {
X int bs = get_back_scroll();
X for (nline = 1; nline <= bs; nline++)
X {
X tpos = back_line(tpos);
X if (tpos == NULL_POSITION)
X break;
X if (tpos <= pos)
X {
X back(nline, position(TOP), 1, 0);
X return;
X }
X }
X } else if ((nline = onscreen(pos)) >= 0)
X {
X /*
X * The line is currently displayed.
X * Just scroll there.
X */
X forw(nline, position(BOTTOM_PLUS_ONE), 1, 0);
X return;
X }
X
X /*
X * Line is not on screen.
X * Remember where we were; clear and paint the screen.
X */
X if (ch_seek(pos))
X {
X error("Cannot seek to that position");
X return;
X }
X lastmark();
X prepaint(pos);
X}
X
X/*
X * The table of marks.
X * A mark is simply a position in the file.
X */
X#define NMARKS (27) /* 26 for a-z plus one for quote */
X#define LASTMARK (NMARKS-1) /* For quote */
Xstatic POSITION marks[NMARKS];
X
X/*
X * Initialize the mark table to show no marks are set.
X */
X#ifdef __STDC__
Xvoid init_mark (void)
X#else
X public void
Xinit_mark()
X#endif
X{
X int i;
X
X for (i = 0; i < NMARKS; i++)
X marks[i] = NULL_POSITION;
X}
X
X/*
X * See if a mark letter is valid (between a and z).
X */
X#ifdef __STDC__
Xstatic int badmark (int c)
X#else
X static int
Xbadmark(c)
X int c;
X#endif
X{
X if (c < 'a' || c > 'z')
X {
X error("Choose a letter between 'a' and 'z'");
X return (1);
X }
X return (0);
X}
X
X/*
X * Set a mark.
X */
X#ifdef __STDC__
Xvoid setmark (int c)
X#else
X public void
Xsetmark(c)
X int c;
X#endif
X{
X if (badmark(c))
X return;
X marks[c-'a'] = position(TOP);
X}
X
X#ifdef __STDC__
Xvoid lastmark (void)
X#else
X public void
Xlastmark()
X#endif
X{
X marks[LASTMARK] = position(TOP);
X}
X
X/*
X * Go to a previously set mark.
X */
X#ifdef __STDC__
Xvoid gomark (int c)
X#else
X public void
Xgomark(c)
X int c;
X#endif
X{
X POSITION pos;
X
X if (c == '\'')
X pos = marks[LASTMARK];
X else if (badmark(c))
X return;
X else
X pos = marks[c-'a'];
X
X if (pos == NULL_POSITION)
X error("mark not set");
X else
X jump_loc(pos);
X}
X
X/*
X * Get the backwards scroll limit.
X * Must call this function instead of just using the value of
X * back_scroll, because the default case depends on sc_height and
X * top_scroll, as well as back_scroll.
X */
X#ifdef __STDC__
Xint get_back_scroll (void)
X#else
X public int
Xget_back_scroll()
X#endif
X{
X if (back_scroll >= 0)
X#ifdef AMIGA
X return (back_scroll < sc_height? back_scroll: sc_height - 1);
X#else
X return (back_scroll);
X#endif
X if (top_scroll)
X return (sc_height - 2);
X return (sc_height - 1);
X}
X
X/*
X * Search for the n-th occurence of a specified pattern,
X * either forward (direction == '/'), or backwards (direction == '?').
X */
X#ifdef __STDC__
Xvoid search (int direction, char *pattern, register int n)
X#else
X public void
Xsearch(direction, pattern, n)
X int direction;
X char *pattern;
X register int n;
X#endif
X{
X register int search_forward = (direction == '/');
X POSITION pos, linepos;
X
X#if RECOMP
X char *re_comp();
X char *errmsg;
X
X /*
X * (re_comp handles a null pattern internally,
X * so there is no need to check for a null pattern here.)
X */
X if ((errmsg = re_comp(pattern)) != NULL)
X {
X error(errmsg);
X return;
X }
X#else
X#if REGCMP
X#ifdef AMIGA
X static regexp *cpattern = NULL;
X#else
X char *regcmp();
X static char *cpattern = NULL;
X#endif
X
X if (pattern == NULL || *pattern == '\0')
X {
X /*
X * A null pattern means use the previous pattern.
X * The compiled previous pattern is in cpattern, so just use it.
X */
X if (cpattern == NULL)
X {
X error("No previous regular expression");
X return;
X }
X } else
X {
X /*
X * Otherwise compile the given pattern.
X */
X#ifdef AMIGA
X regexp *s;
X#else
X char *s;
X#endif
X if ((s = regcmp(pattern, 0)) == NULL)
X {
X#ifdef AMIGA
X /* regexp had already displayed a more specific
X error message
X */
X#else
X error("Invalid pattern");
X#endif
X return;
X }
X if (cpattern != NULL)
X free((char *)cpattern);
X
X cpattern = s;
X }
X#else
X static char lpbuf[100];
X static char *last_pattern = NULL;
X
X if (pattern == NULL || *pattern == '\0')
X {
X /*
X * Null pattern means use the previous pattern.
X */
X if (last_pattern == NULL)
X {
X error("No previous regular expression");
X return;
X }
X pattern = last_pattern;
X } else
X {
X strcpy(lpbuf, pattern);
X last_pattern = lpbuf;
X }
X#endif
X#endif
X
X /*
X * Figure out where to start the search.
X */
X
X if (position(TOP) == NULL_POSITION)
X {
X /*
X * Nothing is currently displayed.
X * Start at the beginning of the file.
X * (This case is mainly for first_cmd searches,
X * for example, "+/xyz" on the command line.)
X */
X pos = (POSITION)0;
X } else if (!search_forward)
X {
X /*
X * Backward search: start just before the top line
X * displayed on the screen.
X */
X pos = position(TOP);
X } else if (top_search)
X {
X /*
X * Forward search and "start from top".
X * Start at the second line displayed on the screen.
X */
X pos = position(TOP_PLUS_ONE);
X } else
X {
X /*
X * Forward search but don't "start from top".
X * Start just after the bottom line displayed on the screen.
X */
X pos = position(BOTTOM_PLUS_ONE);
X }
X
X if (pos == NULL_POSITION)
X {
X /*
X * Can't find anyplace to start searching from.
X */
X error("Nothing to search");
X return;
X }
X
X for (;;)
X {
X /*
X * Get lines until we find a matching one or
X * until we hit end-of-file (or beginning-of-file
X * if we're going backwards).
X */
X#ifdef AMIGA
X if (chk_sigs())
X#else
X if (sigs)
X#endif
X /*
X * A signal aborts the search.
X */
X return;
X
X if (search_forward)
X {
X /*
X * Read the next line, and save the
X * starting position of that line in linepos.
X */
X linepos = pos;
X pos = forw_raw_line(pos);
X } else
X {
X /*
X * Read the previous line and save the
X * starting position of that line in linepos.
X */
X pos = back_raw_line(pos);
X linepos = pos;
X }
X
X if (pos == NULL_POSITION)
X {
X /*
X * We hit EOF/BOF without a match.
X */
X error("Pattern not found");
X return;
X }
X
X /*
X * Test the next line to see if we have a match.
X * This is done in a variety of ways, depending
X * on what pattern matching functions are available.
X */
X#if REGCMP
X if ( (regex(cpattern, line) != NULL)
X#else
X#if RECOMP
X if ( (re_exec(line) == 1)
X#else
X if ( (match(pattern, line))
X#endif
X#endif
X && (--n <= 0) )
X /*
X * Found the matching line.
X */
X break;
X }
X
X jump_loc(linepos);
X}
X
X
X#if (!REGCMP) && (!RECOMP)
X/*
X * We have neither regcmp() nor re_comp().
X * We use this function to do simple pattern matching.
X * It supports no metacharacters like *, etc.
X */
X static int
Xmatch(pattern, buf)
X char *pattern, *buf;
X{
X register char *pp, *lp;
X
X for ( ; *buf != '\0'; buf++)
X {
X for (pp = pattern, lp = buf; *pp == *lp; pp++, lp++)
X if (*pp == '\0' || *lp == '\0')
X break;
X if (*pp == '\0')
X return (1);
X }
X return (0);
X}
X#endif
X
END_OF_FILE
if test 22479 -ne `wc -c <'Less1.4Z/src/prim.c'`; then
echo shar: \"'Less1.4Z/src/prim.c'\" unpacked with wrong size!
fi
# end of 'Less1.4Z/src/prim.c'
fi
echo shar: End of archive 4 \(of 7\).
cp /dev/null ark4isdone
MISSING=""
for I in 1 2 3 4 5 6 7 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked all 7 archives.
rm -f ark[1-9]isdone
else
echo You still need to unpack the following archives:
echo " " ${MISSING}
fi
## End of shell archive.
exit 0
--
Mail submissions (sources or binaries) to <amiga@uunet.uu.net>.
Mail comments to the moderator at <amiga-request@uunet.uu.net>.
Post requests for sources, and general discussion to comp.sys.amiga.misc.